﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using AgilePlannerDT.Data;
using AgilePlannerDT.Utils;
using AgilePlannerDT.Persister;
using AgilePlannerDT.Persister.Impl;
using AgilePlannerDT.Application;
using AgilePlannerDT.Display.CustomWidgets;
using System.Collections.Specialized;
using System.Net.Sockets;
using AgilePlannerDT.Persister.Impl.Socket;
using AgilePlannerDT.Application.Commands.Impl;
using AgilePlannerDT.ThirdPartySync;

namespace AgilePlannerDT.Display.Impl
{
    /// <summary>
    /// Interaction logic for FloatingToolBox.xaml
    /// </summary>
    public partial class FloatingToolBox : DisplayObjectImpl, PlannerDataChangeListener
    {
        #region Constants

        protected readonly double LOST_FOCUS_OPACITY = 0.45;
        protected readonly double GOT_FOCUS_OPACITY = 1;

        #endregion

        #region Attributes

        AsynchronousPersister persister = null;
        HelpDialog help;

        public delegate void WebServiceURLChangedEventHandler(string uri);
        public event WebServiceURLChangedEventHandler OnWebServiceURLChanged;
        public delegate void DisconnectButtonClickedEventHandler();
        public event DisconnectButtonClickedEventHandler OnDisconnectButtonClicked;
        public delegate void GotProjectNames(List<String> str);
        private bool _connectedToAPServer = false;

        #endregion

        #region Properties

        public AsynchronousPersister Persister
        {
            get { return persister; }
            set
            {
                if (persister != null)
                {
                    persister.RemovePlannerDataChangeListener(this);
                }

                persister = value;
                persister.AddPlannerDataChangeListener(this);
                _connectedToAPServer = true;
                connectButton.Content = "Disconnect";
                refreshButton.IsEnabled = true;
                joinButton.IsEnabled = true;
                DisplayStatus("Connected to server", false);
                persister.GetProjectNames();
            }
        }

        #endregion

        #region Constructors


        public FloatingToolBox(AgilePlannerApplication mainWindow)
            : base(mainWindow)
        {
            InitializeComponent();
            center = new Point(CardConstants.FLOATING_TOOLBOX_DEFAULT_WIDTH / 2, CardConstants.FLOATING_TOOLBOX_DEFAULT_HEIGHT / 2);
            DataContext = this;
            isTossingEnabled = true;
            isRNTEnabled = true;

            InitializeTransformations();
            InitializeAnimations();
            InitializeDelegates();
            InitializeColorBox();

            //create rotation around the center of the card
            rotate.CenterX = this.Width/ 2;
            rotate.CenterY = this.Height / 2;

            translateOnlyArea.Opacity = 0;
            translateOnlyArea.IsHitTestVisible = false;

            pin.Opacity = 0;
            pin.Click += new RoutedEventHandler(pin_Click);
            
            joinGrid.Visibility = Visibility.Collapsed;
            exitDialog.Visibility = Visibility.Collapsed;
            voteDialog.Visibility = Visibility.Collapsed;
            synchGrid.Visibility = Visibility.Collapsed;
            this.ConfigTab.Visibility = Visibility.Collapsed;

            DisplayStatus("Not connected", true);

            //initilize jazz combobox
            this.priorityComboBox.Items.Add("Agile Planner");
            this.priorityComboBox.Items.Add("Server");
            this.priorityComboBox.SelectedIndex = 0;

            this.serverComboBox.Items.Add("Team Foundation");
            this.serverComboBox.Items.Add("Jazz");
            this.serverComboBox.SelectedIndex = 0;
            //initialize URL combobox
            if (Properties.Settings.Default.HostNames != null)
            {
                if (Properties.Settings.Default.HostNames.Count > 0)
                {
                    serverUriComboBox.Items.Clear();

                    foreach (string host in Properties.Settings.Default.HostNames)
                    {
                        serverUriComboBox.Items.Add(host);
                    }

                    if(Properties.Settings.Default.LastHost != null)
                    {
                        int index = serverUriComboBox.Items.IndexOf(Properties.Settings.Default.LastHost.ToString());
                        serverUriComboBox.SelectedIndex = index;
                    }
                    else
                    {
                        serverUriComboBox.SelectedIndex = 0;
                    }
                }
                else
                {
                    serverUriComboBox.Items.Clear();
                    serverUriComboBox.Items.Add(Properties.Settings.Default.AgilePlannerDT_APWebservice_APWebserviceService.ToString());
                    serverUriComboBox.Items.Add(Properties.Settings.Default.LocalHost.ToString());
                    serverUriComboBox.SelectedIndex = 0;
                }
            }
            else
            {
                serverUriComboBox.Items.Clear();
                serverUriComboBox.Items.Add(Properties.Settings.Default.AgilePlannerDT_APWebservice_APWebserviceService.ToString());
                serverUriComboBox.Items.Add(Properties.Settings.Default.LocalHost.ToString());
                serverUriComboBox.SelectedIndex = 0;
            }

            if(serverUriComboBox.Items.Count > 1)
            {
                //TODO find a way to disable expander
            }

            refreshButton.IsEnabled = false;
        }

        private void InitializeColorBox()
        {
            this.RedTextBox.Background =  new SolidColorBrush(CardConstants.RED);
            this.AquaTextBox.Background = new SolidColorBrush(CardConstants.AQUA);
            this.BlueTextBox.Background = new SolidColorBrush(CardConstants.BLUE);
            this.GrayTextBox.Background = new SolidColorBrush(CardConstants.GRAY);
            this.greenButton.Background = new SolidColorBrush(CardConstants.GREEN);
            this.KhakiTextBox.Background = new SolidColorBrush(CardConstants.KHAKI);
            this.PeachTextBox.Background = new SolidColorBrush(CardConstants.PEACH);
            this.PinkTextBox.Background = new SolidColorBrush(CardConstants.PINK);
           
            this.WhiteTextBox.Background = new SolidColorBrush(CardConstants.WHITE);
            this.YellowTextBox.Background = new SolidColorBrush(CardConstants.YELLOW);
       
        }
 

        #endregion

        #region Initialization

        private void InitializeDelegates()
        {
            animationStoryBoard.Completed += new EventHandler(animationStoryBoard_Completed);

            aquaButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            blueButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            grayButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            greenButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            khakiButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            peachButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            pinkButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            redButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            whiteButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            yellowButton.Click += new RoutedEventHandler(ColorPaletteButton_Click);
            minimizeButton.Click += new RoutedEventHandler(minimizeButton_Click);
            this.synchButton.Click += new RoutedEventHandler(synchButton_Click);
            this.colorButton.Click += new RoutedEventHandler(colorButton_Click);
            this.ColorBoxExitButton.Click += new RoutedEventHandler(colorButton_Click);
            this.ColorBoxSaveButton.Click += new RoutedEventHandler(ColorBoxSaveButton_Click);
            this.addUserButton.Click += new RoutedEventHandler(addUserButton_Click);
            this.removeUserButton.Click += new RoutedEventHandler(removeUserButton_Click);
            projectsAvailableComboBox.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonDown);
            projectsAvailableComboBox.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonUp);
            projectsAvailableComboBox.PreviewMouseMove += new MouseEventHandler(VisualChildren_PreviewMouseMove);
            projectsAvailableComboBox.LostFocus += new RoutedEventHandler(projectsAvailableComboBox_LostFocus);
        //    projectsAvailableComboBox.
       //     GotProjectNames haveGotNames = new GotProjectNames(OnGotProjectNames);
            serverUriComboBox.LostFocus += new RoutedEventHandler(serverUriComboBox_LostFocus);

            serverUriComboBox.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonDown);
            serverUriComboBox.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonUp);
            serverUriComboBox.PreviewMouseMove += new MouseEventHandler(VisualChildren_PreviewMouseMove);

            MouseLeave += new MouseEventHandler(FloatingToolBox_MouseLeave);
            MouseEnter += new MouseEventHandler(FloatingToolBox_MouseEnter);

            joinMenuButton.Click += new RoutedEventHandler(joinMenuButton_Click);
            helpButton.Click += new RoutedEventHandler(helpButton_Click);
            exitButton.Click += new RoutedEventHandler(exitButton_Click);

            exitButton.TouchDown += new EventHandler<TouchEventArgs>(exitButton_TouchDown);

            connectButton.Click += new RoutedEventHandler(connectButton_Click);
            joinButton.Click += new RoutedEventHandler(joinButton_Click);
            voteButton.Click += new RoutedEventHandler(voteButton_Click);
            startVotingButton.Click += new RoutedEventHandler(startVotingButton_Click);
            stopVotingButton.Click += new RoutedEventHandler(stopVotingButton_Click);
            clearVotingButton.Click += new RoutedEventHandler(clearVotingButton_Click);
            refreshButton.Click +=new RoutedEventHandler(refreshButton_Click);
            exitConfirmButton.Click += new RoutedEventHandler(exitConfirmButton_Click);
            exitCancelButton.Click += new RoutedEventHandler(exitCancelButton_Click);

            //jazz
            this.okButton.Click += new RoutedEventHandler(okButton_Click);
            this.restoreButton.Click += new RoutedEventHandler(restoreButton_Click);

            aquaButton.Background = new SolidColorBrush(CardConstants.AQUA);
            blueButton.Background = new SolidColorBrush(CardConstants.BLUE);
            grayButton.Background = new SolidColorBrush(CardConstants.GRAY);
            greenButton.Background = new SolidColorBrush(CardConstants.GREEN);
            khakiButton.Background = new SolidColorBrush(CardConstants.KHAKI);
            peachButton.Background = new SolidColorBrush(CardConstants.PEACH);
            pinkButton.Background = new SolidColorBrush(CardConstants.PINK);
            redButton.Background = new SolidColorBrush(CardConstants.RED);
            whiteButton.Background = new SolidColorBrush(CardConstants.WHITE);
            yellowButton.Background = new SolidColorBrush(CardConstants.YELLOW);

            List<Button> buttons = new List<Button> {aquaButton, blueButton, grayButton, greenButton,
                khakiButton, peachButton, pinkButton, redButton, whiteButton, yellowButton, 
                exitButton, helpButton, joinMenuButton};

            foreach (Button btn in buttons)
            {
                btn.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonDown);
                btn.PreviewMouseLeftButtonUp += new MouseButtonEventHandler(VisualChildren_PreviewMouseLeftButtonUp);
                btn.PreviewMouseMove += new MouseEventHandler(VisualChildren_PreviewMouseMove);
            }
        }

        void exitButton_TouchDown(object sender, TouchEventArgs e)
        {
            throw new NotImplementedException();
        }

        void removeUserButton_Click(object sender, RoutedEventArgs e)
        {
            if (removeUserListBox.SelectedItem!=null)
            {
                TeamMember newMember = new AgilePlannerDT.Data.Impl.TeamMemberDataObject(removeUserListBox.SelectedItem.ToString());
                if (Persister is AsyncWrapperPersister)
                {
                    Persister.RemoveTeamMember(newMember);
                    Persister.Connect(this.persister.Project.Name);
                }
                else
                {
                    Persister.RemoveTeamMember(newMember);
                }
            }
        }

        void addUserButton_Click(object sender, RoutedEventArgs e)
        {

            if (!addUserTextBox.Text.Trim().Equals(""))
            {
                TeamMember newMember = new AgilePlannerDT.Data.Impl.TeamMemberDataObject(addUserTextBox.Text);
                if (Persister is AsyncWrapperPersister)
                {
                    Persister.AddTeamMember(newMember);
                    Persister.Connect(this.persister.Project.Name);
                }
                else
                {
                    Persister.AddTeamMember(newMember);
                }
            }
        
        }

        void ColorBoxSaveButton_Click(object sender, RoutedEventArgs e)
        {
            Legend newLegend = new AgilePlannerDT.Data.Impl.LegendDataObject(this.AquaTextBox.Text,this.BlueTextBox.Text,this.GrayTextBox.Text,this.GreenTextBox.Text,this.KhakiTextBox.Text,this.PeachTextBox.Text,this.PinkTextBox.Text,this.RedTextBox.Text,this.WhiteTextBox.Text,this.YellowTextBox.Text);
            Persister.UpdateLegend(newLegend);
        }

        void colorButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.ConfigTab.Visibility == Visibility.Collapsed)
                this.ConfigTab.Visibility = Visibility.Visible;
            else
                this.ConfigTab.Visibility = Visibility.Collapsed;
        }

        void restoreButton_Click(object sender, RoutedEventArgs e)
        {
            this.synchBar.Items.Clear();
            TextBlock txtb = new TextBlock();
            txtb.Foreground = Brushes.Red;

            synchBar.Items.Add(txtb);
            if (this.urlTextBox.Text.Trim().Equals("") || this.userNameTextBox.Text.Trim().Equals("") || this.passwordTextBox.Password.Trim().Equals(""))
            {
                txtb.Text = "Incorrect Login Information";
            }
            else
            {
                txtb.Text = "Restoring.......";
                if (this.app.Project == null)
                    txtb.Text = "Not yet select project";
                else if (!(this.app.Persister is AsyncXMLSocketPersister))
                    txtb.Text = "Not connected to remote server. Not available on local mode.";
                else
                {
                    Dictionary<string, string> messageData = new Dictionary<string, string>(){{"syncUrl",this.urlTextBox.Text},
                                                                                 //      {"conflictPriority",(string)this.priorityComboBox.SelectedValue},
                                                                                       {"username", this.userNameTextBox.Text},
                                                                                       {"password",this.passwordTextBox.Password}
                                                                                       //{"url", "zeus"}
                                                                                      };
                    this.app.Persister.SynchWithJazz(AgilePlannerDT.Data.Impl.MessageDataObject.RESTORE_TO_JAZZ, messageData);

                }
            }
        }

        //jazz connect ok button
        void okButton_Click(object sender, RoutedEventArgs e)
        {
                this.synchBar.Items.Clear();
                TextBlock txtb = new TextBlock();
                txtb.Foreground = Brushes.Red;
              
                synchBar.Items.Add(txtb);
                if (this.urlTextBox.Text.Trim().Equals("") || this.userNameTextBox.Text.Trim().Equals("") || this.passwordTextBox.Password.Trim().Equals(""))
                {
                    txtb.Text = "Incorrect Login Information";
                }
                else
                {
                    txtb.Text = "Connecting.......";
                    if (this.app.Project == null)
                        txtb.Text = "Not yet select project";
                    //else if (!(this.app.Persister is AsyncXMLSocketPersister))
                    //    txtb.Text = "Not connect to remote server.Not available on local mode";
                    else// do sync
                    {
                        
                        Priority priority = Priority.AgilePlanner;
                        if (!this.priorityComboBox.SelectedValue.Equals("Agile Planner"))
                        {
                            priority = Priority.Server;
                        }
                        if ("Team Foundation".Equals((string)this.serverComboBox.SelectedValue))
                        {
                            SyncronizeCommand command = new SyncronizeCommand(
                                this.app.Persister,
                                this.urlTextBox.Text,
                                this.userNameTextBox.Text,
                                this.passwordTextBox.Password,
                                priority
                            );
                            try
                            {
                                txtb.Text = "Syncronizing...";
                                command.execute();
                                txtb.Text = "Refreshing UI...";
                                txtb.Text = "Done.";
                            }
                            catch (Exception ex)
                            {
                            }
                        }
                        else if (this.serverComboBox.SelectedValue.Equals("Jazz"))
                        {
                            Dictionary<string, string> messageData = new Dictionary<string, string>(){{"syncUrl",this.urlTextBox.Text},
                                                                                       {"conflictPriority",(string)this.priorityComboBox.SelectedValue},
                                                                                       {"username", this.userNameTextBox.Text},
                                                                                       {"password",this.passwordTextBox.Password}
                                                                                       //{"url", "zeus"}
                                                                                      };
                            this.app.Persister.SynchWithJazz(AgilePlannerDT.Data.Impl.MessageDataObject.SYNC_WITH_JAZZ, messageData);
                        }
                    }
                }
         }

        void synchButton_Click(object sender, RoutedEventArgs e)
        {
            if (this.synchGrid.Visibility == Visibility.Collapsed)
                synchGrid.Visibility = Visibility.Visible;
            else
                synchGrid.Visibility = Visibility.Collapsed;
        }

        private void ArrengeCard()
        {
            
        }

        void minimizeButton_Click(object sender, RoutedEventArgs e)
        {
           // this.Visibility = Visibility.Hidden;
            this.FadeOut();
            //throw new NotImplementedException();
        }


        #endregion

        #region Custom Event Handling

        protected override void OnMouseDoubleClick(MouseButtonEventArgs e)
        {
            base.OnMouseDoubleClick(e);

            if (IsPinned)
            {
                IsPinned = false;
                pin.Opacity = 0;
            }
            else
            {
                IsPinned = true;
                pin.Opacity = 1;
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            Point actual = RelativeToAbsoluteCoordinates(e.GetPosition(this));
            Point actualRelative = e.GetPosition(this);

            if (e.LeftButton.Equals(MouseButtonState.Pressed) && IsActive)
            {
                //don't do anything when the card is pinned but
                //update the last point
                if (IsPinned)
                {
                    previous = actual;
                    previousRelative = e.GetPosition(this);
                    AddMousePoint(actual);
                    AddTimePoint(DateTime.Now);
                    return;
                }

                //ignore very small movements (should help
                //compensate the imprecision of the DViTs)
                if (Util.GetDistance2D(previous, actual) < CardConstants.MIN_MOVEMENT_THRESHOLD)
                {
                    previous = actual;
                    previousRelative = e.GetPosition(this);
                    AddMousePoint(actual);
                    AddTimePoint(DateTime.Now);
                    return;
                }

                IsDragged = true;
                ApplyRNT(actual);

                AddMousePoint(actual);
                AddTimePoint(DateTime.Now);

                previous = actual;
                previousRelative = e.GetPosition(this);
            }
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {

            base.OnMouseLeftButtonDown(e);

            IsActive = true;

            app.BringToFront(this);

            //Yippie-Ki-Yay ... stops the card from jumping if
            //you click on label or resizerhandle
            rotate.Angle = (double)rotate.GetValue(RotateTransform.AngleProperty);
            trans.X = (double)trans.GetValue(TranslateTransform.XProperty);
            trans.Y = (double)trans.GetValue(TranslateTransform.YProperty);

            animationStoryBoard.Stop(this);

            //clear the list of keyframes or you'll get unexpected
            //results
            translateXAnimation.KeyFrames.Clear();
            translateYAnimation.KeyFrames.Clear();
            rotateAnimation.KeyFrames.Clear();

            translateOnlyArea.Opacity = 1;

            if (IsPinned)
                return;

            Point actual = e.GetPosition(this);

            IsTossed = false;

            //translate only
            if (translateOnlyArea.IsInsideTranslateOnlyArea(e.GetPosition(translateOnlyArea)))
            {
                IsTranslated = true;
                IsResized = false;
            }
            //RNT
            else
            {
                IsTranslated = false;
                IsResized = false;
            }

            previous = RelativeToAbsoluteCoordinates(e.GetPosition(this));
            previousRelative = e.GetPosition(this);

            startTime = DateTime.Now;

            //for tossing we watch the last few mouse coordinates
            recentPoints.Clear();
            recentTime.Clear();
            AddMousePoint(RelativeToAbsoluteCoordinates(actual));
            AddTimePoint(DateTime.Now);
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);

            IsActive = false;

            translateOnlyArea.Opacity = 0;

            if (IsPinned)
                return;

            Point actual = e.GetPosition(this);

            IsResized = false;
            IsDragged = false;

            AddMousePoint(RelativeToAbsoluteCoordinates(actual));
            AddTimePoint(DateTime.Now);

            //check if the movement was fast enough to count as tossing
            double length = Util.GetDistance2D(recentPoints[0], recentPoints[recentPoints.Count - 1]);

            if (!IsResized && IsTossingEnabled && (length > CardConstants.STATIC_FRICTION_COEFFICIENT))
            {
                IsTossed = true;

                //vector along which to move the card
                tossingVector = new Point(recentPoints[recentPoints.Count - 1].X - recentPoints[0].X,
                    recentPoints[recentPoints.Count - 1].Y - recentPoints[0].Y);

                //setting up the vector for the initial moment of the tossing RNT
                initVector = new Point(recentPoints[recentPoints.Count - 1].X - CenterAbsolute.X,
                    recentPoints[recentPoints.Count - 1].Y - CenterAbsolute.Y);

                initAngle = RotationAngle;

                endTime = DateTime.Now;

                if (IsTranslated)
                {
                    ApplyTranslateOnlyTossing();
                }
                else
                {
                    ApplyRNTTossing();
                }
            }

            IsTranslated = false;

            //make sure that we don't have any old points in our watchlist
            recentPoints.Clear();
            recentTime.Clear();
        }

        #endregion

        #region Visual Children Event Handling

        private void pin_Click(object sender, RoutedEventArgs e)
        {
            if (IsPinned)
            {
                IsPinned = false;
                pin.Opacity = 0;
            }
            else
            {
                IsPinned = true;
                pin.Opacity = 1;
            }
        }

        private void connectButton_Click(object sender, RoutedEventArgs e)
        {
            //if user is already connected to APServer, disconnect and 
            //toggle the button lable to "connect" again
            if (_connectedToAPServer)
            {
                if(this.persister is AsyncXMLSocketPersister)
                    ((AsyncXMLSocketPersister)this.Persister).stop();

                connectButton.Content = "Connect";
                OnDisconnectButtonClicked();
                DisplayStatus("Disconnected", false);
                //clear project combobox since we are not connected to APServer
                projectsAvailableComboBox.Items.Clear();
                refreshButton.IsEnabled = false;
                joinButton.IsEnabled = false;
                _connectedToAPServer = false;
                return;
            }


            DisplayStatus("Connecting to server ... ", false);
            projectsAvailableComboBox.Items.Clear();

            if (OnWebServiceURLChanged != null)
            {
                if (Properties.Settings.Default.HostNames == null)
                    Properties.Settings.Default.HostNames = new StringCollection();

                if (!Properties.Settings.Default.HostNames.Contains(serverUriComboBox.SelectedItem.ToString()))
                    Properties.Settings.Default.HostNames.Add(serverUriComboBox.SelectedItem.ToString());
                try
                {
                    OnWebServiceURLChanged(serverUriComboBox.SelectedItem.ToString());
                }
                catch (FormatException)
                {
                    DisplayStatus("Invalid URL Format", true);
                }
                catch (SocketException)
                {
                    DisplayStatus("Unable to connect to the IP", true);
                }
              

            }
        }

        private void refreshButton_Click(object sender, RoutedEventArgs e)
        {
            if (Persister != null)
            {
                this.projectsAvailableComboBox.Items.Clear();
                Persister.GetProjectNames();
            }
            else
            {
                DisplayStatus("Cannot refresh, not connected to server", true);
            }
        }


        private void projectsAvailableComboBox_LostFocus(object sender, RoutedEventArgs e)
        {
            string projectName = ((ComboBox)sender).Text;

            if (!projectsAvailableComboBox.Items.Contains(projectName))
            {
                int index = projectsAvailableComboBox.Items.Add(projectName);
                projectsAvailableComboBox.SelectedIndex = index;
            }
        }

        private void serverUriComboBox_LostFocus(object sender, RoutedEventArgs e)
        {
            
            string hostName = ((ComboBox)sender).Text;

            if (!serverUriComboBox.Items.Contains(hostName))
            {
                int index = serverUriComboBox.Items.Add(hostName);
                serverUriComboBox.SelectedIndex = index;
            }
        }

        private void VisualChildren_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            OnMouseMove(e);
        }

        private void VisualChildren_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            OnMouseLeftButtonUp(e);
        }

        private void VisualChildren_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            OnMouseLeftButtonDown(e);
        }
/*
        private void optionsButton_Click(object sender, RoutedEventArgs e)
        {
            
        }
*/
        private void helpButton_Click(object sender, RoutedEventArgs e)
        {
            if (help == null)
            {
                help = new HelpDialog();

                //double offsetX, offsetY;
                //offsetX = Math.Max(help.ActualWidth, help.Width) + 50;
                //offsetY = Math.Max(help.ActualHeight, help.Height) / 2 - Math.Max(Height, ActualHeight) / 2;

                canvas.Children.Add(help);
         //       help.Margin = new Thickness(-800, -200, 50, 0);
            }
            else if (canvas.Children.Contains(help))
            {
                canvas.Children.Remove(help);
            }
            else
            {
                canvas.Children.Add(help);
            }
        }

        private void exitButton_Click(object sender, RoutedEventArgs e)
        {
            exitDialog.Visibility = Visibility.Visible;
        }

        private void exitConfirmButton_Click(object sender, RoutedEventArgs e) 
        {
            if (this.Persister != null && this.Persister is AsyncXMLSocketPersister)
            {
                ((AsyncXMLSocketPersister)this.Persister).stop();
            }

            this.app.Close();
        }

        private void exitCancelButton_Click(object sender, RoutedEventArgs e)
        {
            if(exitDialog.Visibility != Visibility.Collapsed)
                exitDialog.Visibility = Visibility.Collapsed;
        }

        private void joinMenuButton_Click(object sender, RoutedEventArgs e)
        {
            if (joinGrid.Visibility == Visibility.Collapsed)
                joinGrid.Visibility = Visibility.Visible;
            else
                joinGrid.Visibility = Visibility.Collapsed;
        }

        private void animationStoryBoard_Completed(object sender, EventArgs e)
        {
            trans.X = translateXAnimation.KeyFrames[translateXAnimation.KeyFrames.Count - 1].Value;
            trans.Y = translateYAnimation.KeyFrames[translateYAnimation.KeyFrames.Count - 1].Value;

            //if the card was only translated you don't have to update the rotation angle!
            if (rotateAnimation.KeyFrames.Count > 0)
                rotate.Angle = rotateAnimation.KeyFrames[rotateAnimation.KeyFrames.Count - 1].Value;

            //clear the keyframes, they are no longer needed
            translateXAnimation.KeyFrames.Clear();
            translateYAnimation.KeyFrames.Clear();
            rotateAnimation.KeyFrames.Clear();
        }

        private void FloatingToolBox_MouseLeave(object sender, MouseEventArgs e)
        {
            Opacity = LOST_FOCUS_OPACITY;
        }

        private void FloatingToolBox_MouseEnter(object sender, MouseEventArgs e)
        {
            Opacity = GOT_FOCUS_OPACITY;
        }

        private void ColorPaletteButton_Click(object sender, RoutedEventArgs e)
        {
            app.DefaultColor = (Color)new CardColorConverter().ConvertFrom(((Button)sender).Background);
        }

        private void joinButton_Click(object sender, RoutedEventArgs e)
        {
            if (Persister != null)
            {
                if (projectsAvailableComboBox.SelectedIndex != -1)
                {
                    Persister.Connect(projectsAvailableComboBox.SelectedItem.ToString());
                    DisplayStatus("Loading project data ...", false);
                }
                else
                {
                    DisplayStatus("Cannot join, no project selected", true);
                }
            }
            else
            {
                DisplayStatus("Cannot join, not connected to a server", true);
            }
        }

        #endregion

        #region Dot Voting Event Handlers

        private void voteButton_Click(object sender, RoutedEventArgs e)
        {
             voteDialog.Visibility = Visibility.Visible;
        }

        private void startVotingButton_Click(object sender, RoutedEventArgs e)
        {
            voteDialog.Visibility = Visibility.Collapsed;
            if (persister != null)
            {
                DisplayStatus("Voting started", false);
                this.app.IsVotingEnabled = true;
                this.app.Persister.StartVoting();
            }
        }

        private void stopVotingButton_Click(object sender, RoutedEventArgs e)
        {
            voteDialog.Visibility = Visibility.Collapsed;
            if (persister != null)
            {
                DisplayStatus("Voting stopped", false);
                this.app.IsVotingEnabled = false;
                this.app.Persister.StopVoting();
            }
        }

        private void clearVotingButton_Click(object sender, RoutedEventArgs e)
        {
            voteDialog.Visibility = Visibility.Collapsed;
            if (persister != null)
            {
                DisplayStatus("Votes cleared", false);
                this.app.IsVotingEnabled = false;
                this.app.ClearVoteDots();
                this.app.Persister.ClearVotes();
            }
        }

        #endregion

        #region PlannerDataChangeListener Members

        public void OnGotProjectNames(List<string> str)
        {
            projectsAvailableComboBox.Items.Clear();

            if (str.Count > 0)
            {
                foreach (String name in str)
                {
                    projectsAvailableComboBox.Items.Add(name);
                }

                projectsAvailableComboBox.SelectedIndex = 0;
            }

        }

        public void OnLoadedProject(Project project)
        {
            Legend legend = project.Legend;

            aquaButton.Content = legend.Aqua;
            blueButton.Content = legend.Blue;
            grayButton.Content = legend.Gray;
            greenButton.Content = legend.Green;
            khakiButton.Content = legend.Khaki;
            peachButton.Content = legend.Peach;
            pinkButton.Content = legend.Pink;
            redButton.Content = legend.Red;
            whiteButton.Content = legend.White;
            yellowButton.Content = legend.Yellow;

            this.AquaTextBox.Text = legend.Aqua;
            this.BlueTextBox.Text = legend.Blue;
            this.GrayTextBox.Text = legend.Gray;
            this.GreenTextBox.Text = legend.Green;
            this.KhakiTextBox.Text = legend.Khaki;
            this.PeachTextBox.Text = legend.Peach;
            this.PinkTextBox.Text = legend.Pink;
            this.RedTextBox.Text = legend.Red;
            this.WhiteTextBox.Text = legend.White;
            this.YellowTextBox.Text = legend.Yellow;
            this.AquaTextBox.IsEnabled = true;
            this.BlueTextBox.IsEnabled = true;
            this.GrayTextBox.IsEnabled = true;
            this.GreenTextBox.IsEnabled = true;
            this.KhakiTextBox.IsEnabled = true;
            this.PeachTextBox.IsEnabled = true;
            this.PinkTextBox.IsEnabled = true;
            this.RedTextBox.IsEnabled = true;
            this.WhiteTextBox.IsEnabled = true;
            this.YellowTextBox.IsEnabled = true;
            this.ColorBoxSaveButton.IsEnabled = true;

            DisplayStatus("Load finished", false); 

            this.OnUpdateTeamMember(project.TeamMemberChildren);
        }

        public void OnUpdateTeamMember(List<TeamMember> members)
        {
            this.addUserTextBox.Clear();
            if (members != null)
            {
                this.removeUserListBox.Items.Clear();
                foreach (TeamMember member in members)
                {
                    removeUserListBox.Items.Add(member.Name);
                }
            }
        }
                     
        //this method is only for local mode call
        public void OnUpdatedLegend(Legend legend)
        {
            aquaButton.Content = legend.Aqua;
            blueButton.Content = legend.Blue;
            grayButton.Content = legend.Gray;
            greenButton.Content = legend.Green;
            khakiButton.Content = legend.Khaki;
            peachButton.Content = legend.Peach;
            pinkButton.Content = legend.Pink;
            redButton.Content = legend.Red;
            whiteButton.Content = legend.White;
            yellowButton.Content = legend.Yellow;

            this.AquaTextBox.Text = legend.Aqua;
            this.BlueTextBox.Text = legend.Blue;
            this.GrayTextBox.Text = legend.Gray;
            this.GreenTextBox.Text = legend.Green;
            this.KhakiTextBox.Text = legend.Khaki;
            this.PeachTextBox.Text = legend.Peach;
            this.PinkTextBox.Text = legend.Pink;
            this.RedTextBox.Text = legend.Red;
            this.WhiteTextBox.Text = legend.White;
            this.YellowTextBox.Text = legend.Yellow;
        }

        public void OnCreatedBacklog(Backlog backlog) { }

        public void OnCreatedIteration(Iteration iteration, bool isCreatedByRemoteClient) { }

        public void OnCreatedProject(Project project) { }

        public void OnCreatedStoryCard(StoryCard storycard) { }

        public void OnDeletedStoryCard(StoryCard storycard) { }

        public void OnDeletedIteration(Iteration iteration) { }

        public void OnDeletedBacklog(Backlog backlog) { }

        public void OnDeletedProject(bool deleted) { }

        public void OnUndeletedBacklog(Backlog backlog) { }

        public void OnUndeletedIteration(Iteration iteration) { }

        public void OnUndeletedStoryCard(StoryCard storycard) { }

        public void OnMovedStoryCardToNewParent(StoryCard storycard) { }

        public void OnUpdatedBacklog(Backlog backlog) { }

        public void OnUpdatedIteration(Iteration iteration) { }

        public void OnUpdatedStoryCard(StoryCard storycard) { }

        public void OnAsynchronousException(Exception exception) { }

        public void OnArrangedProject(Project project) { }

        public void OnGotProjectNamesForLoginEvent(List<string> list) { }

        

        #endregion


        #region PlannerDataChangeListener Members


        public void OnMouseMove(MouseMove move)
        {
          
        }

        public void OnStartedVoting() 
        {
            DisplayStatus("Voting started", false);
        }

        public void OnStoppedVoting() 
        {
            DisplayStatus("Voting stopped", false);
        }

        public void OnVotedCard(VoteDot dot) { }

        public void OnClearVotes() 
        {
            DisplayStatus("Votes cleared", false);
        }

        #endregion

        public void OnCardMinimized(long ID,bool isMinimized)
        {
        }

        #region PlannerDataChangeListener Members


        public void OnOtherClientDisconnected(int clientID  )
        {
            
        }

        #endregion

        #region PlannerDataChangeListener Members


        public void OnLiveUpdated(LiveUpdate update)
        {
        }

        #endregion

        
        #region Automation

        /// <summary>
        /// Provides an implementation of this control as per the WPF structure.
        /// </summary>
        /// <returns>Returns a new AutomationPeer for this type.</returns>
        protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
        {
            return new FloatingToolBoxAutomationPeer(this);
        }

        public class FloatingToolBoxAutomationPeer : DisplayObjectImplAutomationPeer
        {
            FloatingToolBox host;

            /// <summary>
            /// Inits a new instance from the base class.
            /// </summary>
            /// <param name="control">The calling control.</param>
            public FloatingToolBoxAutomationPeer(FloatingToolBox control)
                : base(control)
            {
                host = control;
            }

            /// <summary>
            /// This is the name of the UIElement associated with the AutomationPeer.
            /// </summary>
            /// <returns>The name of this control type.</returns>
            protected override string GetClassNameCore()
            {
                return "FloatingToolBox";
            }

            /// <summary>
            /// Sets the AutomationID
            /// </summary>
            /// <returns>The name of this display object.</returns>
            protected override string GetAutomationIdCore()
            {
                return "FloatingToolBox:" + host.ID;
            }

            /// <summary>
            /// FloatingToolBox objects cannot resize.
            /// </summary>
            public override bool CanResize 
            {
                get 
                {
                    return false;
                }
            }
        }

        #endregion

        #region MultiTouchEvent

        public override void OnTouchDown(Point p)
        {
            
           // exitButton.RaiseEvent(Button.

            base.OnTouchDown(p);
            IsActive = true;

            app.BringToFront(this);

            //Yippie-Ki-Yay ... stops the card from jumping if
            //you click on label or resizerhandle
            rotate.Angle = (double)rotate.GetValue(RotateTransform.AngleProperty);
            trans.X = (double)trans.GetValue(TranslateTransform.XProperty);
            trans.Y = (double)trans.GetValue(TranslateTransform.YProperty);

            animationStoryBoard.Stop(this);

            //clear the list of keyframes or you'll get unexpected
            //results
            translateXAnimation.KeyFrames.Clear();
            translateYAnimation.KeyFrames.Clear();
            rotateAnimation.KeyFrames.Clear();

            translateOnlyArea.Opacity = 1;

            if (IsPinned)
                return;

            Point actual = this.getPosition(p,this);

            IsTossed = false;

            //translate only
            if (translateOnlyArea.IsInsideTranslateOnlyArea(this.getPosition(p,translateOnlyArea)))
            {
                IsTranslated = true;
                IsResized = false;
            }
            //RNT
            else
            {
                IsTranslated = false;
                IsResized = false;
            }

            previous = p;
            previousRelative = this.getPosition(p,this);

            startTime = DateTime.Now;

            //for tossing we watch the last few mouse coordinates
            recentPoints.Clear();
            recentTime.Clear();
            AddMousePoint(RelativeToAbsoluteCoordinates(actual));
            AddTimePoint(DateTime.Now);
        }

        public override void OnTouchMove(Point p)
        {
            base.OnTouchMove(p);

            Point actual = p;
            Point actualRelative = this.getPosition(p,this);

            if (IsActive)
            {
                //don't do anything when the card is pinned but
                //update the last point
                if (IsPinned)
                {
                    previous = actual;
                    previousRelative = this.getPosition(p,this);
                    AddMousePoint(actual);
                    AddTimePoint(DateTime.Now);
                    return;
                }

                //ignore very small movements (should help
                //compensate the imprecision of the DViTs)
                if (Util.GetDistance2D(previous, actual) < CardConstants.MIN_MOVEMENT_THRESHOLD)
                {
                    previous = actual;
                    previousRelative = this.getPosition(p,this);
                    AddMousePoint(actual);
                    AddTimePoint(DateTime.Now);
                    return;
                }

                IsDragged = true;
                ApplyRNT(actual);

                AddMousePoint(actual);
                AddTimePoint(DateTime.Now);

                previous = actual;
                previousRelative = this.getPosition(p,this);
            }
        }

        public override void OnTouchUp(Point p)
        {
            base.OnTouchUp(p);
            
            IsActive = false;

            translateOnlyArea.Opacity = 0;

            if (IsPinned)
                return;

            Point actual = this.getPosition(p,this);

            IsResized = false;
            IsDragged = false;

            AddMousePoint(RelativeToAbsoluteCoordinates(actual));
            AddTimePoint(DateTime.Now);

            //check if the movement was fast enough to count as tossing
            double length = Util.GetDistance2D(recentPoints[0], recentPoints[recentPoints.Count - 1]);

            if (!IsResized && IsTossingEnabled && (length > CardConstants.STATIC_FRICTION_COEFFICIENT))
            {
                IsTossed = true;

                //vector along which to move the card
                tossingVector = new Point(recentPoints[recentPoints.Count - 1].X - recentPoints[0].X,
                    recentPoints[recentPoints.Count - 1].Y - recentPoints[0].Y);

                //setting up the vector for the initial moment of the tossing RNT
                initVector = new Point(recentPoints[recentPoints.Count - 1].X - CenterAbsolute.X,
                    recentPoints[recentPoints.Count - 1].Y - CenterAbsolute.Y);

                initAngle = RotationAngle;

                endTime = DateTime.Now;

                if (IsTranslated)
                {
                    ApplyTranslateOnlyTossing();
                }
                else
                {
                    ApplyRNTTossing();
                }
            }

            IsTranslated = false;

            //make sure that we don't have any old points in our watchlist
            recentPoints.Clear();
            recentTime.Clear();
        
        }

        private void exitButton_TouchUp(object sender, TouchEventArgs e)
        {

        }

    /*    private Point getPosition(Point p, UIElement element)
        {
            //           Point relativePoint = (Point)this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new GetRelativePoint(this.windowCanvas.TranslatePoint),p, (UIElement)activatedCard);

            //       return (Point)((AgilePlannerMainWindow)(this.app)).Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render,new GetPosition(((AgilePlannerMainWindow)(this.app)).getCanvas().TranslatePoint),p, element);
            return ((AgilePlannerMainWindow)(this.app)).getCanvas().TranslatePoint(p, element);
        }*/
        #endregion


        public void OnUpdatedProject(Project project)
        {
            OnLoadedProject(project);
        }

        public void DisplayStatus(String status, bool isError)
        {
            joinGrid.Height = 124; // this is the default height for the join grid

            //if this is an error message, change the text to red
            if (isError)
                statusString.Foreground = new SolidColorBrush(Colors.Red);

            // if the string is too long, expand the join grid to fit all the message in
            if (status.Length > 35)
                joinGrid.Height = 144;

            statusString.Text = status;
        }
    }
}